using System;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Web;
using System.Web.Hosting;

namespace Framework.Library.Core.Utils.IO
{
    public class FileUtils
    {
        public static FileSystemInfo GetFileSystemInfo(string path)
        {
            if (File.Exists(path))
            {
                return new FileInfo(path);
            }
            else if (Directory.Exists(path))
            {
                return new DirectoryInfo(path);
            }

            return null;
        }

        /// <summary>
        /// Removes invalid file name characters from the specified string.
        /// </summary>
        /// <param name="s">The filename string.</param>
        /// <returns></returns>
        public static string ToValidFileName(string s)
        {
            return ToValidFileName(s, string.Empty, null);
        }

        public static string ToValidFileName(string s, string invalidReplacement)
        {
            return ToValidFileName(s, invalidReplacement, null);
        }

        public static string ToValidFileName(string s, string invalidReplacement, string spaceReplacement)
        {
            var sb = new StringBuilder(s);

            foreach (char invalidFileNameChar in Path.GetInvalidFileNameChars())
            {
                if (invalidReplacement != null)
                    sb.Replace(invalidFileNameChar.ToString(), invalidReplacement);
            }

            if (spaceReplacement != null)
                sb.Replace(" ", spaceReplacement);

            return sb.ToString();
        }

        public static string MapPath(string path)
        {
            if (Path.IsPathRooted(path))
            {
                return path;
            }
            else if (HostingEnvironment.IsHosted)
            {
                return HostingEnvironment.MapPath(path);
            }
            else if (VirtualPathUtility.IsAppRelative(path))
            {
                string physicalPath = VirtualPathUtility.ToAbsolute(path, "/");
                physicalPath = physicalPath.Replace('/', '\\');
                physicalPath = physicalPath.Substring(1);
                physicalPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, physicalPath);

                return physicalPath;
            }
            else
            {
                throw new Exception("Could not resolve non-rooted path.");
            }
        }

        [DllImport("msvcrt.dll", SetLastError = true)]
        private static extern int _mkdir(string path);

        public static DirectoryInfo CreateDirectory(string path)
        {
            var oDir = new DirectoryInfo(Path.GetFullPath(path));
            try
            {
                if (!oDir.Exists)
                    oDir.Create();

                return oDir;
            }
            catch
            {
                CreateDirectoryUsingDll(oDir);

                return new DirectoryInfo(path);
            }
        }

        private static void CreateDirectoryUsingDll(DirectoryInfo dir)
        {
            var oDirsToCreate = new ArrayList();
            while (dir != null && !dir.Exists)
            {
                oDirsToCreate.Add(dir.FullName);
                dir = dir.Parent;
            }

            if (dir == null)
                throw (new DirectoryNotFoundException("Directory \"" + oDirsToCreate[oDirsToCreate.Count - 1] +
                                                      "\" not found."));

            for (int i = oDirsToCreate.Count - 1; i >= 0; i--)
            {
                var sPath = (string) oDirsToCreate[i];
                int iReturn = _mkdir(sPath);

                if (iReturn != 0)
                    throw new ApplicationException("Error calling [msvcrt.dll]:_wmkdir(" + sPath + "), error code: " +
                                                   iReturn);
            }
        }

        public static bool ArrayContains(Array array, object value, IComparer comparer)
        {
            foreach (object item in array)
            {
                if (comparer.Compare(item, value) == 0)
                    return true;
            }
            return false;
        }
    }
}